package com.transaction.simulate.service.impl;

import com.transaction.common.base.PageInfo;
import com.transaction.common.util.BeanUtil;
import com.transaction.common.util.ConstUtil;
import com.transaction.common.util.DateUtil;
import com.transaction.common.util.PageUtil;
import com.transaction.simulate.mapper.ChannelMapper;
import com.transaction.simulate.mapper.FundMapper;
import com.transaction.simulate.mapper.FundRateMapper;
import com.transaction.simulate.mapper.TransMapper;
import com.transaction.simulate.model.dto.*;
import com.transaction.simulate.model.vo.ChannelAccountVo;
import com.transaction.simulate.model.vo.FundVo;
import com.transaction.simulate.service.ElContractService;
import com.transaction.simulate.service.TransService;
import com.transaction.simulate.util.AssembleFileUtil;
import com.transaction.simulate.util.SequenceUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class TransServiceImpl implements TransService {

    private static Logger LOGGER = LoggerFactory.getLogger(TransServiceImpl.class);

    @Autowired
    private FundMapper fundMapper;

    @Autowired
    private ChannelMapper channelMapper;

    @Autowired
    private TransMapper transMapper;

    @Autowired
    private SequenceUtil sequenceUtil;

    @Autowired
    private ElContractService elContractService;

    @Autowired
    private FundRateMapper fundRateMapper;

    @Override
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public void generateChannelTransData(ChannelAccountVo channelAccountVo) {
        List<ChannelTrans> channelTransList = new ArrayList<>();
        List<Account> accounts = channelAccountVo.getTransAccounts();

        String channelCode = channelAccountVo.getChannelCode();
        String fundCode = channelAccountVo.getFundCode();
        String transDate = channelAccountVo.getTransDate();
        FundVo fundVo = fundMapper.getFundList(channelCode,fundCode).get(0);
        Channel channel = channelMapper.selectChannelByChannelCode(channelCode);

        accounts.forEach(v->{
            ChannelTrans channelTrans = setChannelTrans(v,channelAccountVo,channel,fundVo,transDate);
            channelTransList.add(channelTrans);
        });
        //生成电子合同数据
        transMapper.generateChannelTransData(channelTransList);
        elContractService.generateChannelElContract(channelAccountVo);
        LOGGER.info("主线程执行完成");
    }


    private ChannelTrans setChannelTrans(Account v, ChannelAccountVo channelAccountVo, Channel channel, FundVo fundVo,String transDate) {

        ChannelTrans channelTrans = new ChannelTrans();

        String channelCode = channelAccountVo.getChannelCode();
        String fundCode = channelAccountVo.getFundCode();

        BigDecimal applicationVol = channelAccountVo.getApplicationVol();
        BigDecimal applicationAmount = channelAccountVo.getApplicationAmount();

        if(applicationAmount.compareTo(BigDecimal.ZERO) != 0){
            //查询费率
            FundRate fundRate = fundRateMapper.selectFundRateByChannelFundAndAmount(channelCode,fundCode,applicationAmount);
            if(Objects.nonNull(fundRate)){
                applicationAmount = applicationAmount.multiply(new BigDecimal(1).add(fundRate.getFundRate()));
            }
        }

        String appSheetSerialNo = DateUtil.formatDate(new Date(System.currentTimeMillis()), DateUtil.FORMAT_STR_TIME14) + sequenceUtil.getSixDigitSequence();
        String transActionTime = DateUtil.formatDate(new Date(),DateUtil.FORMAT_STR_TIME6);

        String creatorCode = channel.getCreatorCode();

        channelTrans.setChannelCode(channelCode);
        channelTrans.setAppSheetSerialNo(appSheetSerialNo);
        channelTrans.setFundCode(fundCode);
        channelTrans.setTransactionDate(transDate);
        channelTrans.setTransactionTime(transActionTime);
        channelTrans.setTransactionAccountId(v.getTransactionAccountId());
        channelTrans.setDistributorCode(creatorCode);
        channelTrans.setApplicationVol(applicationVol);
        channelTrans.setApplicationAmount(applicationAmount);

        String fundStatus = fundVo.getFundStatus();
        if(Objects.equals("1",fundStatus)){
            channelTrans.setBusinessCode("020");
        }else{
            channelTrans.setBusinessCode("022");
        }

        if(applicationVol.compareTo(BigDecimal.ZERO) != 0){
            channelTrans.setBusinessCode("024");
        }

        channelTrans.setBranchCode(creatorCode);
        return channelTrans;
    }

    @Override
    public List<ChannelTrans> getChannelTrans(ChannelTrans channelTrans, PageInfo pageInfo) {
        PageUtil.StartPage(pageInfo);
        return transMapper.getChannelTrans(channelTrans,pageInfo);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public void generateChannelTransFile(String channelCode, String transDate, List<String> dateRange) {
        AssembleFileUtil.generateChannelFile(channelCode,transDate,dateRange, ConstUtil.FILE_TYPE_03);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public void generateChannel31ElContractFile(String channelCode, String transDate, List<String> dateRange) {
        AssembleFileUtil.generateChannelFile(channelCode,transDate,dateRange,ConstUtil.FILE_TYPE_31);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public void generateChannel43ElContractFile(String channelCode, String transDate, List<String> dateRange) {
        AssembleFileUtil.generateChannelFile(channelCode,transDate,dateRange,ConstUtil.FILE_TYPE_43);
    }

    @Override
    public List<Map<String, Object>> getTransToMap(String channelCode, List<String> dateRange) {
        return transMapper.getTransToMap(channelCode,dateRange);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public void updateChannelTrans(String channelCode, List<Map<String, Object>> dataList) {
        transMapper.updateChannelTrans(channelCode,dataList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public void insertChannelTrans(String channelCode, List<Map<String, Object>> dataList) {
        transMapper.deleteChannelTrans(channelCode,dataList);
        transMapper.insertChannelTrans(channelCode,dataList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public void handleConfirmChannelTrans(String channelCode, List<Map<String, Object>> dataList) {
        //插入确认表
        if(CollectionUtils.isNotEmpty(dataList)){
            transMapper.insertChannelTransConfirm(channelCode,dataList);
        }
        //更新交易表
        List<Map<String, Object>> updateTransData = exchangeChannelTransList(dataList,ConstUtil.TRANS_APPLICATION_CONFIRM);
        if(CollectionUtils.isNotEmpty(updateTransData)){
            updateChannelTrans(channelCode,updateTransData);
        }
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public List<Map<String, Object>> exchangeChannelTransList(List<Map<String, Object>> dataList, String transTypes) {
        List<Map<String, Object>> retList = new ArrayList<>();
        for (Map<String,Object> map : dataList) {
            String businessCode = MapUtils.getString(map,"BUSINESSCODE");
            if(transTypes.contains(businessCode)){
                retList.add(map);
            }
        }
        return retList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public void insertReconciliation(String channelCode, List<Map<String, Object>> dataList) {
        transMapper.deleteReconciliation(channelCode, MapUtils.getString(dataList.get(0),"TRANSACTIONCFMDATE"));
        transMapper.insertReconciliation(channelCode,dataList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insertBonus(String channelCode, List<Map<String, Object>> dataList) {
        transMapper.deleteBonus(channelCode,MapUtils.getString(dataList.get(0),"DIVIDENTDATE"));
        transMapper.insertBonus(channelCode,dataList);
    }

    @Override
    public List<Reconciliation> getReconciliation(Reconciliation reconciliation, PageInfo pageInfo) {
        PageUtil.StartPage(pageInfo);
        return transMapper.getReconciliation(reconciliation,pageInfo);
    }

    @Override
    public List<Bonus> getBonus(Bonus bonus, PageInfo pageInfo) {
        PageUtil.StartPage(pageInfo);
        return transMapper.getBonus(bonus,pageInfo);
    }

    @Override
    public List<ElContract> getElContract(ElContract elContract, PageInfo pageInfo) {
        PageUtil.StartPage(pageInfo);
        return transMapper.getElContract(elContract,pageInfo);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public void deleteAll() {
        transMapper.deleteAll();
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public void deleteAllElContract() {
        transMapper.deleteAllElContract();
    }

    @Override
    @Transactional(propagation = Propagation.SUPPORTS,rollbackFor = Exception.class)
    public List<ChannelTransCfm> getChannelTransCfm(ChannelTransCfm channelTransCfm, PageInfo pageInfo) {
        PageUtil.StartPage(pageInfo);
        return transMapper.getChannelTransCfm(channelTransCfm);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public void deleteAllChannelTransCfm() {
        transMapper.deleteAllChannelTransCfm();
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public List<TransVolStatistics> getTransVolStatistics(TransVolStatistics transVolStatistics, PageInfo pageInfo) {
        if(CollectionUtils.isNotEmpty(transVolStatistics.getStatisticsDimensionalityList())){
            transVolStatistics.setStatisticsDimensionality(String.join(",",transVolStatistics.getStatisticsDimensionalityList()));
        }
        //1.查询购买记录
        PageUtil.StartPage(pageInfo);
        List<TransVolStatistics> transList = transMapper.selectTransData(transVolStatistics);

        //2.查询确认记录
        List<TransVolStatistics> transCfmList = transMapper.selectTransCfmData(transVolStatistics);
        Map<String,TransVolStatistics> transCfmMap = null;
        if(CollectionUtils.isNotEmpty(transCfmList)){
            transCfmMap = transCfmList.stream().collect(Collectors.toMap(
                    TransVolStatistics->TransVolStatistics.getChannelCode() + TransVolStatistics.getFundCode() + TransVolStatistics.getTransactionAccountId(),
                    TransVolStatistics->TransVolStatistics));
        }

        //3.查询分红记录
        List<TransVolStatistics> bonusList = transMapper.selectBonusData(transVolStatistics);
        Map<String,TransVolStatistics> bonusMap = new HashMap<>();
        if(CollectionUtils.isNotEmpty(bonusList)) {
            bonusMap = bonusList.stream().collect(Collectors.toMap(
                    TransVolStatistics -> TransVolStatistics.getChannelCode() + TransVolStatistics.getFundCode() + TransVolStatistics.getTransactionAccountId(),
                    TransVolStatistics -> TransVolStatistics));
        }

        //4.查询对账记录
        List<TransVolStatistics> reconciliationList = transMapper.selectReconciliationData(transVolStatistics);
        Map<String,TransVolStatistics> reconciliationMap = new HashMap<>();
        if(CollectionUtils.isNotEmpty(reconciliationList)) {
            reconciliationMap = reconciliationList.stream().collect(Collectors.toMap(
                    TransVolStatistics -> TransVolStatistics.getChannelCode() + TransVolStatistics.getFundCode() + TransVolStatistics.getTransactionAccountId(),
                    TransVolStatistics -> TransVolStatistics));
        }

        //5.组装数据
        Map<String, TransVolStatistics> finalTransCfmMap = transCfmMap;
        Map<String, TransVolStatistics> finalBonusMap = bonusMap;
        Map<String, TransVolStatistics> finalReconciliationMap = reconciliationMap;

        transList.forEach(v->{
            String key = v.getChannelCode() + v.getFundCode() + v.getTransactionAccountId();
            //合并确认数据
            TransVolStatistics transCfm = finalTransCfmMap.get(key);
            if(Objects.nonNull(transCfm)){
                BeanUtil.comparePropertyOverWriteNullFields(transCfm,v);
            }
            //合并分红数据
            TransVolStatistics bonusCfm = finalBonusMap.get(key);
            if(Objects.nonNull(bonusCfm)){
                BeanUtil.comparePropertyOverWriteNullFields(bonusCfm,v);
            }
            //合并对账数据
            TransVolStatistics reconciliationCfm = finalReconciliationMap.get(key);
            if(Objects.nonNull(reconciliationCfm)){
                BeanUtil.comparePropertyOverWriteNullFields(reconciliationCfm,v);
            }
        });

        //6.计算份额是否平整,或者还没确认份额
        transList.forEach(v->{
            //130 + 122 + 分红 - 124 -142 -150 - 对账
            BigDecimal volCheckResult = v.getSubResult()
                    .add(v.getAllotConfirm())
                    .add(v.getBonus())
                    .subtract(v.getRedeemConfirmVol())
                    .subtract(v.getForceRedeemVol())
                    .subtract(v.getLiquidationVol())
                    .subtract(v.getTotalVol());
            v.setVolCheckResult(volCheckResult);
        });
        return transList;
    }
}
